package sdiff.tests;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class ReissTableOutput
{
    private static int getFirstMatchExtraResults(String filename)
    {
        if (filename.startsWith("ASTResolving")) {
            return 18;
        } else if (filename.startsWith("ArrayReference")) {
            return 12;
        } else if (filename.startsWith("BaseTypes")) {
            return 10;
        } else if (filename.startsWith("BuildPathsPropertyPage")) {
            return 13;
        } else if (filename.startsWith("CompilationUnitDocumentProvider")) {
            return 17;
        } else if (filename.startsWith("CPListLabelProvider")) {
            return 12;
        } else if (filename.startsWith("DeltaProcessor")) {
            return 12;
        } else if (filename.startsWith("DialogCustomize")) {
            return 8;
        } else if (filename.startsWith("DirectoryDialog")) {
            return 3;
        } else if (filename.startsWith("DoubleCache")) {
            return 12;
        } else if (filename.startsWith("FontData")) {
            return 14;
        } else if (filename.startsWith("GC2")) {
            return 11;
        } else if (filename.startsWith("GC")) {
            return 13;
        } else if (filename.startsWith("JavaCodeScanner")) {
            return 13;
        } else if (filename.startsWith("JavaModelManager")) {
            return 6;
        } else if (filename.startsWith("JavaPerspectiveFactory")) {
            return 8;
        } else if (filename.startsWith("PluginSearchScope")) {
            return 8;
        } else if (filename.startsWith("RefreshLocal")) {
            return 6;
        } else if (filename.startsWith("ResourceCompareInput")) {
            return 15;
        } else if (filename.startsWith("ResourceInfo")) {
            return 13;
        } else if (filename.startsWith("SaveManager")) {
            return 6;
        } else if (filename.startsWith("TabFolder")) {
            return 12;
        }
        throw new RuntimeException("Can't find extra results for file " +filename);
    }
    public static void merge(Map<String,ReissScore> total, 
            Map<String,ReissScore> results)
    {
        for (Map.Entry<String,ReissScore> entry : results.entrySet()) {
            String method=entry.getKey();
            ReissScore score=entry.getValue();
            if (!total.containsKey(method))
                total.put(method, new ReissScore());
            total.get(method).plus(score);
        }
    }
    
    public static void removeFirstResults(Map<String,ReissScore> map)
    {
        for (Map.Entry<String,ReissScore> entry : map.entrySet()) {
            
        }
    }
    
    public static void main(String[] args)
    throws Exception
    {
        String dir="/Users/jspacco/projects/smallChanges/scam2009/data/reiss";
        File[] files=new File(dir).listFiles();
        //PrintStream out=new PrintStream(dir+"/results");
        PrintStream out=System.out;
        Map<String,ReissScore> total=new HashMap<String,ReissScore>();

        out.println("method\tcorrect\tchange\telim\tspur\tavg");
        for (File file : files) {
            if (file.isDirectory())
                continue;
            if (file.getName().startsWith("BaseType"))
                continue;
            Map<String,ReissScore> map=readReissInput(file.getAbsolutePath());
            merge(total, map);
            //printStuff(map, out);
        }
        //printPercentage(total, out);
        printPercentageLatex(total, out);
        //printCounts(total, out);

    }

    /**
     * @param map
     * @param ps
     */
    private static void printPercentage(Map<String, ReissScore> map, PrintStream ps)
    {
        for (Map.Entry<String,ReissScore> entry : map.entrySet()) {
            String method=entry.getKey();
            ReissScore score=entry.getValue();
            double total=score.getNumCorrectChanges()+score.getNumIncorrect();
            double incorrect=score.getNumIncorrect();
            
            NumberFormat f=NumberFormat.getPercentInstance();
            
            ps.print(method+"\t");
            ps.print(f.format(score.getNumCorrectChanges()/total)+"\t");
            ps.print(f.format(score.getNumMismatchedChanges()/incorrect)+"\t");
            ps.print(f.format(score.getNumEliminatedDeletes()/incorrect)+"\t");
            ps.print(f.format(score.getNumSpuriousDeletes()/incorrect)+"\t");
            //ps.print(avgTime+"\t");
            ps.println();
        }
    }
    
    private static void printPercentageLatex(Map<String, ReissScore> map, PrintStream ps)
    {
        for (Map.Entry<String,ReissScore> entry : map.entrySet()) {
            String method=entry.getKey();
            ReissScore score=entry.getValue();
            double total=score.getNumCorrectChanges()+score.getNumIncorrect();
            double incorrect=score.getNumIncorrect();
            
            NumberFormat f=NumberFormat.getPercentInstance();
            
            ps.print(method+"&\t");
            ps.print(f.format(score.getNumCorrectChanges()/total).replace("%","\\%")+"\t");
            ps.print("&\t");
            ps.print(f.format(score.getNumMismatchedChanges()/incorrect).replace("%","\\%")+"\t");
            ps.print("&\t");
            ps.print(f.format(score.getNumEliminatedDeletes()/incorrect).replace("%","\\%")+"\t");
            ps.print("&\t");
            ps.print(f.format(score.getNumSpuriousDeletes()/incorrect).replace("%","\\%")+"\t");
            ps.print("\\\\");
            //ps.print(avgTime+"\t");
            ps.println();
        }
    }
    private static void printCounts(Map<String, ReissScore> map, PrintStream ps)
    {
        for (Map.Entry<String,ReissScore> entry : map.entrySet()) {
            String method=entry.getKey();
            ReissScore score=entry.getValue();
            
            ps.print(method+"\t");
            ps.print(score.getNumCorrectChanges()+"\t");
            ps.print(score.getNumMismatchedChanges()+"\t");
            ps.print(score.getNumEliminatedDeletes()+"\t");
            ps.print(score.getNumSpuriousDeletes()+"\t");
            //ps.print(avgTime+"\t");
            ps.println();
        }
    }
    
    public static Map<String,ReissScore> readReissInput(String filename)
    throws SAXException, IOException, ParserConfigurationException
    {
        try {
            DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
            Document doc = docBuilder.parse(new File(filename));
            // normalize text representation
            doc.getDocumentElement().normalize();
            //System.out.println ("Root of doc: " +doc.getDocumentElement().getNodeName()); 

            NodeList scoreList = doc.getElementsByTagName("SCORES").item(0).getChildNodes();
            int numScores= scoreList.getLength();
            //System.out.println("Found " +numScores+" scores");
            Map<String,ReissScore> map=new HashMap<String,ReissScore>();
            if (numScores<1)
                return map;

            for(int v=0; v<scoreList.getLength() ; v++){
                Node scoreNode = scoreList.item(v);

                if(scoreNode.getNodeType() == Node.ELEMENT_NODE){
                    Element score=(Element)scoreNode;
                    String method=score.getAttribute("METHOD");
                    int correct=Integer.parseInt(score.getAttribute("CORRECT"));
                    int change=Integer.parseInt(score.getAttribute("CHANGE"));
                    int elim=Integer.parseInt(score.getAttribute("ELIM"));
                    int spurious=Integer.parseInt(score.getAttribute("SPURRIOUS"));
                    double avgTime=Double.parseDouble(score.getAttribute("AVGTIME"));

                    ReissScore reissScore=new ReissScore();
                    reissScore.setNumCorrectMatches(correct - getFirstMatchExtraResults(new File(filename).getName()));
                    reissScore.setNumMismatchedChanges(change);
                    reissScore.setNumEliminatedDeletes(elim);
                    reissScore.setNumSpuriousDeletes(spurious);

                    if (!map.containsKey(method)) {
                        map.put(method, new ReissScore());
                    }
                    map.get(method).plus(reissScore);


                }
            }
            return map;
        } catch (SAXParseException e) {
            System.out.println("CAN'T PROCESS " +filename);
            throw e;
        }
    }
}
